#include "server.h"
#include <string>
#include "common.h"
#include <thread>

void sendMsg(server* s,
            websocketpp::connection_hdl hdl,
            std::string msg, 
            websocketpp::frame::opcode::value codeType);

void on_run(server &s, unsigned int port) {
    try {
        // Set logging settings
        s.set_access_channels(websocketpp::log::alevel::all);
        s.set_error_channels(websocketpp::log::elevel::all);
        //s.clear_access_channels(websocketpp::log::alevel::frame_payload);

        // Register our message handler
        s.set_message_handler(bind(&on_message, &s, ::_1, ::_2));
        s.set_http_handler(bind(&on_http, &s, ::_1));
        s.set_fail_handler(bind(&on_fail, &s, ::_1));
        s.set_open_handler(bind(&on_open, &s, ::_1));
        s.set_close_handler(bind(&on_close, ::_1));
        s.set_validate_handler(bind(&validate, &s, ::_1));

        // Initialize ASIO
        s.init_asio();
        s.set_reuse_addr(true);

        // Listen on port
        s.listen(port);
        std::cout <<"listen on " << port << std::endl;
        // Start the server accept loop
        s.start_accept();
        // Start the ASIO io_service run loop
        s.run();
        
    }
    catch (websocketpp::exception const& e) {
        std::cout << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "other exception" << std::endl;
    }
}

void on_stop(server &s)
{
    try {
         s.stop();
    } catch (websocketpp::exception const& e) {
        std::cout << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "other exception" << std::endl;
    }

}

bool validate(server*, websocketpp::connection_hdl) {
    return true;
}

void on_http(server* s, websocketpp::connection_hdl hdl) {
    try {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        websocketpp::http::parser::request rt = con->get_request();
        const std::string& strUri = rt.get_uri();
        const std::string& strMethod = rt.get_method();
        //const std::string& strBody = rt.get_body();	//只针对post时有数据
        const std::string& strHost = rt.get_header("host");
        //const std::string& strVersion = rt.get_version();
        const std::string& g_strRunPath = "D:\\Simulator\\build-Simulator-Desktop_Qt_5_14_2_MinGW_64_bit-Debug";
        std::cout<<"Received one "<< strMethod.c_str() <<"request:"<<strUri.c_str()<<"  thread ID="<< std::this_thread::get_id() <<"  host = "<<strHost<<std::endl;
        if (strMethod.compare("POST") == 0) {
            //对于post提交的，直接跳转到深鸿会 Gitee
            //websocketpp::http::parser::request r;
            con->set_status(websocketpp::http::status_code::value(websocketpp::http::status_code::found));
            con->append_header("location", "https://gitee.com/hiharmonica/harmonica-previewer");
        }
        else if (strMethod.compare("GET") == 0) {
            if (strUri.compare("/") == 0) {
                //请求主页
                con->set_body("Hello WebsocketPP!");
                con->set_status(websocketpp::http::status_code::value(websocketpp::http::status_code::ok));
            }
            else if (strUri.compare("/favicon.ico") == 0) {
                //请求网站图标，读取图标文件，直接返回二进制数据
                static const std::string strIcoPath = g_strRunPath + "server\\Update.ico";
                std::string strBuffer;
                if (ReadFileContent(strIcoPath.c_str(), std::ios_base::binary, strBuffer))
                {
                    con->set_body(strBuffer);
                }
                con->set_status(websocketpp::http::status_code::value(websocketpp::http::status_code::ok));//HTTP返回码 OK
            }
            else if (strUri.compare("/test.html") == 0) {
                //请求一个页面，读取这个页面文件内容然后返回给浏览器
                static const std::string strHtmlPath = g_strRunPath + "/test.html";
                std::string strBuffer;
                int code = websocketpp::http::status_code::ok;
                if (ReadFileContent(strHtmlPath.c_str(), std::ios_base::in, strBuffer))
                {
                    con->set_body(strBuffer);
                }
                else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                    con->set_body("<html><body><div style=\"color:#F000FF;font:14px;font-family: 'Microsoft YaHei';\">温馨提示：</div><div style=\"padding-left: 80px;color:#333333;font:14px;font-family: 'Microsoft YaHei';\">页面被外星人带走啦！</div></body></html>");
                }
                con->set_status(websocketpp::http::status_code::value(code));//HTTP返回码
            }
            else if (strUri.compare("/server/test.jpg") == 0) {
                //上面的页面的HTML中配置了一张图片，因此浏览器回来服务器请求这张图
                static const std::string strImgPath = g_strRunPath + "server\\test.jpg";
                std::string strBuffer;
                int code = websocketpp::http::status_code::ok;
                if (ReadFileContent(strImgPath.c_str(), std::ios_base::binary, strBuffer)) {
                    con->set_body(strBuffer);
                }
                else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                }
                con->set_status(websocketpp::http::status_code::value(code));//HTTP返回码
            }
            else {
                //其他未定义的页面，返回跳转
                con->set_status(websocketpp::http::status_code::value(websocketpp::http::status_code::found));
                con->append_header("location", "https://gitee.com/hiharmonica/harmonica-previewer");
            }
        }

    }
    catch (websocketpp::exception const &e) {
        std::cout << "exception: " << e.what() << std::endl;
    }
    catch(std::exception &e) {
        std::cout << "exception: " << e.what() << std::endl;
    }
    catch(...) {
        std::cout << "other exception" << std::endl;
    }
}

void on_fail(server* s, websocketpp::connection_hdl hdl) {
    server::connection_ptr con = s->get_con_from_hdl(hdl);

    std::cout << "Fail handler: " << con->get_ec() << " " << con->get_ec().message() << std::endl;
}

void on_open(server* s, websocketpp::connection_hdl hdl) {
    //申请websocket upgrade成功之后，调用open_handler函数，回调on_open。
    //在这里，可以获取http请求的地址、参数信息。
    server::connection_ptr con = s->get_con_from_hdl(hdl);
    std::cout << "Open handler" << con->get_ec() << " " << con->get_ec().message() << std::endl;
}

void on_close(websocketpp::connection_hdl hdl) {
    std::cout << "Close handler" << std::endl;
}

// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    /*
        hdl.lock().get() 获得连接标识
        msg->get_payload() 是收到的消息内容
        msg->get_opcode() 是收到消息的类型 ，包含：文本TEXT,二进制BINARY等等
    */
    std::cout << "on_message called with hdl: " << hdl.lock().get()
        << " and message: " << msg->get_payload()
        << std::endl;

    std::string msgBody = msg->get_payload();
    CMessage cMessage = CMessage::parseJson(msgBody);
    if(cMessage.command  == "restart")
    {
        // todo restart engine
        std::cout << "restart engine" << std::endl;
        std::string successMsg = "{ \"section\":\"engine\", \"action\":\"launch\", \"status\":\"success\" }";
        sendMsg(s, hdl, successMsg, msg->get_opcode());
    }else if (cMessage.command  == "exit")
    {
        std::cout << "exit preview" << std::endl;
    }else if (cMessage.command  == "theme")
    {
        std::cout << "change theme" << std::endl;
    }
    
    

}

void sendMsg(server* s,
            websocketpp::connection_hdl hdl,
            std::string msg, 
            websocketpp::frame::opcode::value opCode){
    try {
        /*
            发送消息
            s->send(    
            hdl, //连接
            msg, //消息
            opCode;//消息类型
        */
        s->send(hdl, msg, opCode);
    }
    catch (websocketpp::exception const& e) {
        std::cout << "Echo failed because: "
                  << "(" << e.what() << ")" << std::endl;
    }    
}
